package com.ctg.itrdc.sysmgr.permission.core.realm;

import java.util.List;
import java.util.Map;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ctg.itrdc.sysmgr.permission.core.CtgToken;
import com.ctg.itrdc.sysmgr.permission.core.CtgUser;
import com.ctg.itrdc.sysmgr.permission.core.IConstants;
import com.ctg.itrdc.sysmgr.permission.core.IPermissionService;

public class DbRealm extends AuthorizingRealm {

	public Logger logger = LoggerFactory.getLogger(getClass());

	private IPermissionService permissionService;

	private String algorithmName = "md5";

	private int hashIterations = 1;

	public String getAlgorithmName() {
		return algorithmName;
	}

	public void setAlgorithmName(String algorithmName) {
		this.algorithmName = algorithmName;
	}

	public int getHashIterations() {
		return hashIterations;
	}

	public void setHashIterations(int hashIterations) {
		this.hashIterations = hashIterations;
	}

	public IPermissionService getPermissionService() {
		return permissionService;
	}

	public void setPermissionService(IPermissionService permissionService) {
		this.permissionService = permissionService;
	}

	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof CtgToken;
	}

	// 授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

		// 因为非正常退出，即没有显式调用 SecurityUtils.getSubject().logout()
		// (可能是关闭浏览器，或超时)，但此时缓存依旧存在(principals)，所以会自己跑到授权方法里。
		if (!SecurityUtils.getSubject().isAuthenticated()) {
			doClearCache(principalCollection);
			SecurityUtils.getSubject().logout();
			return null;
		}

		CtgUser shiroUser = (CtgUser) principalCollection.getPrimaryPrincipal();
		Long sysPostId = shiroUser.getSysPostId();
		Long sysUserId = shiroUser.getSysUserId();
		if (sysUserId == null || sysUserId == 0) {
			return null;
		}

		// 添加角色及权限信息
		SimpleAuthorizationInfo sazi = new SimpleAuthorizationInfo();
		List<String> roles = permissionService.getRoleCodes(sysUserId, sysPostId);
		if (roles != null && roles.size() > 0) {
			sazi.addRoles(roles);
		}
		List<String> permissions = permissionService.getPermissions(sysUserId, sysPostId);
		if (permissions != null && permissions.size() > 0) {
			sazi.addStringPermissions(permissions);
		}
		return sazi;
	}

	// 认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

		CtgToken ctgToken = (CtgToken) token;

		// 调用业务方法
		Map<String, Object> user = null;
		String userName = ctgToken.getUsername();

		try {
			user = permissionService.getUserByUsername(userName); // 走sysUser缓存
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new AuthenticationException(e);
		}

		if (user == null) {
			throw new UnknownAccountException("用户不存在");
		}

		// 用户无效状态
		if (!IConstants.S0A.equals(user.get("STATUS_CD"))) {
			throw new LockedAccountException("账户失效状态");
		}

		// TODO 功能不完善
		// 密码无效状态
		// if (!IConstants.S0A.equals(user.get("PWD_STATUS"))) {
		// throw new LockedAccountException("密码失效状态");
		// }

		// 登录超过限制次数
		Integer limitCount = (Integer) user.get("LIMIT_COUNT");
		Integer loginedNum = (Integer) user.get("LOGINED_NUM");
		if (limitCount != null && loginedNum != null && loginedNum > limitCount) {
			throw new LockedAccountException("登录已超过限制次数");
		}

		Long sysUserId = (Long) user.get("SYS_USER_ID");
		String sysUserCode = (String) user.get("SYS_USER_CODE");
		Long staffId = (Long) user.get("STAFF_ID");
		CtgUser ctgUser = new CtgUser(sysUserCode, sysUserId, staffId);
		// 要放在作用域中的东西，请在这里进行操作
		AuthenticationInfo authinfo = new SimpleAuthenticationInfo(ctgUser, user.get("PASSWORD"), getName());
		return authinfo;
	}

	/**
	 * 设定Password校验的Hash算法与迭代次数.
	 */
	public void initCredentialsMatcher() {
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(algorithmName);
		matcher.setStoredCredentialsHexEncoded(false);
		// hash迭代次数
		matcher.setHashIterations(hashIterations);
		setCredentialsMatcher(matcher);
	}

}
